﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;

namespace Dare.Utilities.Model
{
    public class IPAddressData : IConvertible
    {
        long ipAddress;
        public long IpAddress
        {
            get { return ipAddress; }
            set { SetIPAddress(value); }
        }

        string ipAddressString;
        public string IpAddressString
        {
            get { return ipAddressString; }
            set { SetIPAddress(value); }
        }

        public IPAddressData()
        {
            SetIPAddress(0);
        }

        public IPAddressData(long ipAddress)
        {
            SetIPAddress(ipAddress);
        }

        public IPAddressData(string ipAddress)
        {
            SetIPAddress(ipAddress);
        }

        public IPAddressData(IPAddress ipAddress)
        {
            SetIPAddress(ipAddress);
        }

        public void SetIPAddress(long num)
        {
            ipAddress = num & 0x00000000FFFFFFFF;

            StringBuilder sb = new StringBuilder(15);
            sb.Append(num >> 24 & 0xFF).Append('.').Append(num >> 16 & 0xFF).Append('.').Append(num >> 8 & 0xFF).Append('.').Append(num & 0xFF);
            ipAddressString = sb.ToString();
        }

        public static bool TryParse(string s, out IPAddressData result)
        {
            result = new IPAddressData();
            return result.SetIPAddress(s);
        }

        public bool SetIPAddress(string ip)
        {
            if (!String.IsNullOrEmpty(ip))
            {
                string[] parts = ip.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                if (parts.Length != 4) return false;
                long num = 0;

                for (int j = 0, i = 3; i >= 0; i--, j += 8)
                {
                    long tempNum;
                    if (long.TryParse(parts[i], out tempNum))
                    {
                        num += tempNum << j;
                    }
                    else
                    {
                        return false;
                    }
                }

                SetIPAddress(num);
                return true;
            }
            else
            {
                return false;
            }
        }

        public void SetIPAddress(IPAddress ipAddress)
        {
            byte[] bytes = ipAddress.GetAddressBytes();
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes);   //转换成Little-Endian
            }
            SetIPAddress((long)BitConverter.ToUInt32(bytes, 0));
        }

        public IPAddress GetIPAddress()
        {
            byte[] bytes = BitConverter.GetBytes((uint)ipAddress);
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes);   //转换成Big-Endian
            }
            return new IPAddress(bytes);
        }

        public override string ToString()
        {
            return ipAddressString;
        }

        public override int GetHashCode()
        {
            return ipAddress.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj is IPAddressData)
            {
                return ipAddress == (obj as IPAddressData).ipAddress;
            }
            return false;
        }


        public static implicit operator IPAddressData(long num)
        {
            return new IPAddressData(num);
        }

        public static implicit operator IPAddressData(uint num)
        {
            return new IPAddressData((long)num);
        }

        public static implicit operator IPAddressData(ulong num)
        {
            return new IPAddressData((long)num);
        }

        public static implicit operator IPAddressData(string ip)
        {
            return new IPAddressData(ip);
        }

        public static implicit operator long(IPAddressData ipAddress)
        {
            return ipAddress.IpAddress;
        }

        public static implicit operator uint(IPAddressData ipAddress)
        {
            return (uint)ipAddress.IpAddress;
        }

        #region IConvertible 成员

        public TypeCode GetTypeCode()
        {
            return TypeCode.Object;
        }

        public bool ToBoolean(IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public byte ToByte(IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public char ToChar(IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public DateTime ToDateTime(IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public decimal ToDecimal(IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public double ToDouble(IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public short ToInt16(IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public int ToInt32(IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public long ToInt64(IFormatProvider provider)
        {
            return this.IpAddress;
        }

        public sbyte ToSByte(IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public float ToSingle(IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public string ToString(IFormatProvider provider)
        {
            return ToString();
        }

        public object ToType(Type conversionType, IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public ushort ToUInt16(IFormatProvider provider)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public uint ToUInt32(IFormatProvider provider)
        {
            return (uint)IpAddress;
        }

        public ulong ToUInt64(IFormatProvider provider)
        {
            return (ulong)IpAddress;
        }

        #endregion
    }
}
